/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2013 Semtech

Description: Implements the generic UART driver

License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Miguel Luis and Gregory Cristian
*/
#include "board.h"
#include "uart-board.h"
#if defined( USE_USB_CDC )
#include "uart-usb-board.h"
#endif

#include "uart.h"

/*!
 * Number of times the UartPutBuffer will try to send the buffer before
 * returning ERROR
 */
#define TX_BUFFER_RETRY_COUNT                       10

void UartInit(Uart_t *obj, uint8_t uartId, PinNames tx, PinNames rx)
{
    if(obj->IsInitialized == false)
    {
        obj->IsInitialized = true;

        if(uartId == UART_USB_CDC)
        {
#if defined( USE_USB_CDC )
            UartUsbInit(obj, uartId, NC, NC);
#endif
        }
        else
        {
            UartMcuInit(obj, uartId, tx, rx);
        }
    }
}

void UartConfig(Uart_t *obj, UartMode_t mode, uint32_t baudrate, WordLength_t wordLength, StopBits_t stopBits, Parity_t parity, FlowCtrl_t flowCtrl)
{
    if(obj->IsInitialized == false)
    {
        // UartInit function must be called first.
        assert_param(FAIL);
    }
    if(obj->UartId == UART_USB_CDC)
    {
#if defined( USE_USB_CDC )
        UartUsbConfig(obj, mode, baudrate, wordLength, stopBits, parity, flowCtrl);
#endif
    }
    else
    {
        UartMcuConfig(obj, mode, baudrate, wordLength, stopBits, parity, flowCtrl);
    }
}

void UartDeInit(Uart_t *obj)
{
    obj->IsInitialized = false;
    if(obj->UartId == UART_USB_CDC)
    {
#if defined( USE_USB_CDC )
        UartUsbDeInit(obj);
#endif
    }
    else
    {
        UartMcuDeInit(obj);
    }
}

uint8_t UartPutChar(Uart_t *obj, uint8_t data)
{
    if(obj->UartId == UART_USB_CDC)
    {
#if defined( USE_USB_CDC )
        return UartUsbPutChar(obj, data);
#else
        return 255; // Not supported
#endif
    }
    else
    {
        return UartMcuPutChar(obj, data);
    }
}

uint8_t UartGetChar(Uart_t *obj, uint8_t *data)
{
    if(obj->UartId == UART_USB_CDC)
    {
#if defined( USE_USB_CDC )
        return UartUsbGetChar(obj, data);
#else
        return 255; // Not supported
#endif
    }
    else
    {
        return UartMcuGetChar(obj, data);
    }
}

uint8_t UartPutBuffer(Uart_t *obj, uint8_t *buffer, uint16_t size)
{
    if(obj->UartId == UART_USB_CDC)
    {
#if defined( USE_USB_CDC )
        return UartUsbPutBuffer(obj, buffer, size);
#else
        return 255; // Not supported
#endif
    }
    else
    {
        uint8_t retryCount;
        uint16_t i;

        for(i = 0; i < size; i++)
        {
            retryCount = 0;
            while(UartPutChar(obj, buffer[i]) != 0)
            {
                retryCount++;

                // Exit if something goes terribly wrong
                if(retryCount > TX_BUFFER_RETRY_COUNT)
                {
                    return 1; // Error
                }
            }
        }
        return 0; // OK
    }
}

uint8_t UartGetBuffer(Uart_t *obj, uint8_t *buffer, uint16_t size, uint16_t *nbReadBytes)
{
    uint16_t localSize = 0;

    while(localSize < size)
    {
        if(UartGetChar(obj, buffer + localSize) == 0)
        {
            localSize++;
        }
        else
        {
            break;
        }
    }

    *nbReadBytes = localSize;

    if(localSize == 0)
    {
        return 1; // Empty
    }
    return 0; // OK
}
